﻿using AutoMapper;
using Max.PH6_2009A.LowCode.API.Auth;
using Max.PH6_2009A.LowCode.Domain;
using Max.PH6_2009A.LowCode.DTO;
using Max.PH6_2009A.LowCode.IService;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using NPOI.SS.UserModel;

namespace Max.PH6_2009A.LowCode.API.Controllers
{
    /// <summary>
    /// RBAC用户控制器
    /// </summary>
    [Route("rbac/user")]
    [ApiController]
    //[Authorize]
    public class UserController : ControllerBase
    {
        IUserService _service;
        IMapper _map;

        JwtAuth _jwt;
        JwtConfig _config;

        Microsoft.AspNetCore.Hosting.IWebHostEnvironment _host;

        public UserController(IUserService service, IMapper map, JwtAuth jwt, JwtConfig config, IWebHostEnvironment host)
        {
            _service = service;
            _map = map;
            _jwt = jwt;
            _config = config;
            _host = host;
        }


        #region 20230511

        /// <summary>
        /// 递归菜单
        /// </summary>
        /// <returns></returns>
        [HttpGet("menus")]
        public IActionResult GetMenus()
        {
            var result = _service.GetMenus();
            return Ok(result);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        [HttpPost("add/menu")]
        public IActionResult AddMenuByRole(int roleid,List<int> vs)
        {
            _service.AddMenuByRoleID(roleid,vs);
            return Ok(1);
        }

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult Get(int pageIndex, int pageSize, string? key = "")
        {
            string sql = "pr_user_list"; //"select * from tb_user";

            Dapper.DynamicParameters param = new();
            param.Add("@pageIndex", pageIndex);
            param.Add("@pageSize", pageSize);
            param.Add("@name", key ?? "");
            param.Add("@total", 0, System.Data.DbType.Int32, System.Data.ParameterDirection.Output);

            var data = _service.Select(sql, param, System.Data.CommandType.StoredProcedure);
            var result = _map.Map<IEnumerable<UserModel>, IEnumerable<UserOutputDto>>(data);

            int total = param.Get<int>("total");

            return Ok(new { total, result });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult Insert(UserInputDto dto)
        {
            ResponseResultDto result = new();

            var model = _map.Map<UserInputDto, UserModel>(dto);

            //判断是否重名
            string sql = "select * from tb_user where loginname=@loginname";
            var m = _service.Select(sql, model).FirstOrDefault();
            if (m != null)
            {
                result.Code = ResponseResultCode.UserNameRepeat;
                result.Message = "用户名已存在";
                return BadRequest(result);
            }
            _service.Insert(m);

            return Ok(result);
        }


        /// <summary>
        /// 添加用户的同时，添加这个用户属拥有的角色
        /// </summary>
        /// <returns></returns>
        [HttpPost("ur")]
        public IActionResult InsertUserAndRoles(UserInsertRoleDto dto)
        {
            ResponseResultDto result = new();

            if (string.IsNullOrEmpty(dto.LoginName))
            {
                result.Code = ResponseResultCode.UserNameNull;
                result.Message = "用户名不能为空";
                return BadRequest();
            }

            _service.InsertUserAndRoles(dto);
            return Ok(result);
        }


        /// <summary>
        /// 根据用户ID获取这个用户所拥有的角色
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        [HttpGet("byid")]
        public IActionResult GetRoleMenuByRoleId(string userId)
        {
            ResponseResultDto result = new();

            if (string.IsNullOrEmpty(userId))
            {
                result.Code = ResponseResultCode.Failed;
                result.Message = "参数无效";
                return BadRequest(result);
            }

            var data = _service.GetUserRoleByUserId(userId);
            result.Data = data;
            return Ok(result);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost("login")]
        public IActionResult Login(UserInputDto dto)
        {
            ResponseResultDto result = new();
            var data = _service.Login(dto.LoginName, dto.Password);

            //result.Data = data;
            if (data.Item1)
            {

                var token = _jwt.CreateToken(TokenType.Token);
                var refleshToke = _jwt.CreateToken(TokenType.RefleshToken);
                result.Data = new { data.Item3, token, refleshToke };
            }
            else
            {
                result.Code = ResponseResultCode.UserNameNull;
                result.Message = data.Item2;
            }

            return Ok(result);
        }

        /// <summary>
        /// 根据用户ID，获取该用户所拥有的菜单权限列表
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        [HttpGet("menu")]
        public IActionResult GetMenubyUserId(string userId)
        {
            ResponseResultDto result = new();

            var data = _service.GetUserMenu(userId);
            result.Data = data;
            return Ok(result);
        }


        /// <summary>
        /// 删除用户
        /// </summary>
        /// <param name="ls"></param>
        /// <returns></returns>
        [HttpDelete]
        public IActionResult Delete(List<RbacDeleteByIdDto> ls)
        {
            ResponseResultDto dto = new();

            if (ls == null || ls.Count <= 0)
            {
                dto.Code = ResponseResultCode.Failed;
                dto.Message = "参数无效";
                return BadRequest(dto);
            }

            var result = _service.Delete(ls);

            dto.Message = result.Item2;
            if (!result.Item1)
            {
                dto.Code = ResponseResultCode.Failed;
                return BadRequest(dto);
            }

            return Ok(dto);
        }

        /// <summary>
        /// 文件上传
        /// </summary>
        /// <returns></returns>
        [HttpPost("upload")]
        public IActionResult Upload(List<IFormFile> files)
        {
            //====================================可以批量上传
            //通过请求参数（一）
            //IFormFile file //单文件
            //List< IFormFile> files  //多文件
            //(二）
            //var filse = Request.Form.Files;

            //====================================可以自定义保存文件路径（默认：根据当前日期保存为文件夹）
            //要获取wwwroot目录
            //要创建名称为当前日期的目录（文件夹）
            var wwwroot = _host.WebRootPath;
            var date = System.DateTime.Now.ToString("yyyyMMdd");
            var directory = $"{wwwroot}/{date}";
            //创建目录
            if (!System.IO.Directory.Exists(directory))
            {
                System.IO.Directory.CreateDirectory(directory);
            }


            //================================可以限制文件大小(默认不超过1Ｍ)
            //首先要拿上传的文件的大小
            //用这个大小和被限制的大小进行比较
            files.ToList().ForEach(file =>
            {
                var length = file.Length;
                int size = 1; //默认1M
                //1M = 1024KB ,  1Kb = 1024byte
                if (length > size * 1024 * 1024)
                {
                    //这个文件超过1M了，请重新选择
                }

                //================================可以限制文件格式
                //要拿到文件的扩展名（1、截取字符串  2、直接用Path）
                //再去判断是否在我们的限制内
                string ext = System.IO.Path.GetExtension(file.FileName);
                string[] exts = { ".png", ".jpg", ".jpeg", ".gif" }; //限定只能上传图片格式的文件
                if (!exts.ToList().Contains(ext))
                {
                    //这个文件不是我们想要上传的文件
                }

                //==============================自动更改文件名
                //新的文件名+扩展名
                var newFileName = $"{Guid.NewGuid():N}{ext}";

                //新文件所在完整路径
                var newFilePath = System.IO.Path.Combine(directory, newFileName);

                //using (FileStream fs = new FileStream(newFilePath, FileMode.OpenOrCreate))
                using (var stream = System.IO.File.Create(newFilePath))
                {
                    file.CopyTo(stream);
                }
            });




            return Ok();
        }


        /// <summary>
        /// Excel导入到DataBase
        /// </summary>
        /// <returns></returns>
        [HttpPost("import")]
        public IActionResult Import() //IFormFile
        {
            ResponseResultDto dto = new();
            var files = Request.Form.Files;
            if(files== null || files.Count <= 0)
            {
                dto.Code = ResponseResultCode.Failed;
                dto.Message = "请选择文件";
                return Ok(dto);
            }
            var file = files[0];

            //上传
            var path = $"wwwroot/{file.FileName}";
            using (var _stream = new FileStream(path, FileMode.OpenOrCreate))
            {
                file.CopyTo(_stream);
            }

            //读取刚才上传的这个文件 ====NPOI
            //XSSF : 2007以后，即扩展名是.xlsx
            //HSSF：2007以前的，即扩展名是.xls
            var ext = System.IO.Path.GetExtension(file.FileName);

            //1、拿工作簿
            IWorkbook book = null;
            var stream = new FileStream(path, FileMode.Open);
            switch (ext)
            {
                case ".xls":
                    break;
                    book = new NPOI.HSSF.UserModel.HSSFWorkbook(stream);
                case ".xlsx":
                default:
                    book = new NPOI.XSSF.UserModel.XSSFWorkbook(stream);
                    break;
            }

            //2、从工作簿中拿sheet
            var sheet = book.GetSheet("sheet1");

            //3、去sheet里拿每一行和每一列的数据
            //每个sheet里面，有可能包含表头（表头和数据表中字段有对应关系）
            //先拿表头----excel从0行0列开始算
            var headerRolw = sheet.GetRow(0);
            int cellNumber = headerRolw.LastCellNum; //这一行中，有多少列
            for (int i = 0; i < cellNumber; i++)
            {
                var cellName = headerRolw.GetCell(i).StringCellValue;
                Console.Write($"{cellName}|");
            }
            Console.WriteLine("\r\n");
            Console.WriteLine("----------------------------------------------------------");

            List<EmployeeModel> employees = new();
            //处理数据行(得知道这个sheet中具体有多少行，才能循环操作)
            var dataRows = sheet.LastRowNum; //这个sheet中，具体有多少行(包含了表头所在的行)
            for (int i = 1; i <= dataRows; i++)
            {
                #region Console打印

                //var row = sheet.GetRow(i); //拿到数据的具体行
                //for (int c = 0; c < cellNumber; c++)
                //{
                //    var _cell = row.GetCell(c);

                //    if (_cell.CellType == CellType.Numeric)
                //    {
                //        var d = _cell.NumericCellValue;
                //    }
                //    else if(_cell.CellType == CellType.Boolean)
                //    {
                //        var b = _cell.BooleanCellValue;
                //    }

                //    var cellValue = _cell.StringCellValue;
                //    Console.Write($"{cellValue}|");
                //}
                //Console.WriteLine("\r\n");
                //Console.WriteLine("----------------------------------------------------------");

                #endregion

                var _row = sheet.GetRow(i);//拿到具体的行
                EmployeeModel employee = new();

                employee.Name = _row.GetCell(2).StringCellValue;
                employee.Gender = _row.GetCell(3).StringCellValue;
                employee.Age = Convert.ToInt32(_row.GetCell(4).StringCellValue);
                employee.CardNo = _row.GetCell(5).StringCellValue;
                employee.HighestEduction = _row.GetCell(6).StringCellValue;
                employee.Native = _row.GetCell(7).StringCellValue;
                employee.Address = _row.GetCell(8).StringCellValue;
                employee.IsMarry = _row.GetCell(9).StringCellValue == "否" ? false : true;
                employee.illHistory = _row.GetCell(10).StringCellValue;
                employee.Phone = _row.GetCell(11).StringCellValue;
                employee.EMail = _row.GetCell(12).StringCellValue;
                employee.WeiXin = _row.GetCell(13).StringCellValue;
                employee.QQ = _row.GetCell(14).StringCellValue;
                employees.Add(employee);
            }

            _service.InsertMoreEmployee(employees);

            return Ok(dto);
        }

        /// <summary>
        /// 从数据库导出到Excel
        /// </summary>
        /// <returns></returns>
        [HttpPost("export")]
        public IActionResult Export()
        {
            /*
             * 1、需要获取数据（查询后的数据）
             * 2、把这些数据放到excel文件中
             * 3、需要下载这个Excel文件
             * **/
             var data = _service.GetEmployee();

            //把这些数据放到excel中
            /*
             * 1、还没有这个excel文件（需要创建或者给它一个模板文件） 
             * 2、依次填充到excel单元格（导入的时候，是依次每行每个单元格拿出数据）
             * **/
            #region 创建一个新的空的Excel文件
            //var book = new NPOI.XSSF.UserModel.XSSFWorkbook();
            //var sheet = book.CreateSheet("sheet1");
            //var row2 = sheet.CreateRow(2);
            //var cell1 = row2.CreateCell(1);
            //cell1.SetCellValue("姓名");
            #endregion

            #region 根据模板文件进行导出

            //拿到模板文件
            string path = "wwwroot/template/employee_template.xlsx";
            Stream stream = new FileStream(path, FileMode.Open);

            var book = new NPOI.XSSF.UserModel.XSSFWorkbook(stream);
            //这个文件中，sheet已存在，不用创建，可以直接拿过来用
            var sheet = book.GetSheet("sheet1");

            for (int i = 0; i < data.Count(); i++)
            {
                var row = sheet.CreateRow(i + 1);
                var model = data[i];
                row.CreateCell(0).SetCellValue(i + 1);
                row.CreateCell(2).SetCellValue(model.Name);
                row.CreateCell(3).SetCellValue(model.Gender);
                row.CreateCell(4).SetCellValue(model.Age.ToString());
                row.CreateCell(5).SetCellValue(model.CardNo);
                row.CreateCell(6).SetCellValue(model.HighestEduction);
                row.CreateCell(7).SetCellValue(model.Native);
                row.CreateCell(8).SetCellValue(model.Address);
                row.CreateCell(9).SetCellValue((bool)model.IsMarry);
                row.CreateCell(10).SetCellValue(model.illHistory);
                row.CreateCell(11).SetCellValue(model.Phone);
                row.CreateCell(12).SetCellValue(model.EMail);
                row.CreateCell(13).SetCellValue(model.WeiXin);
                row.CreateCell(14).SetCellValue(model.QQ);
            }
            #endregion


            MemoryStream ms = new MemoryStream();
            book.Write(ms);
            //wookbook --- 流 -----文件

            byte[] bytes = ms.ToArray();

            return File(bytes, "application/-excel", $"{System.DateTime.Now.ToString("yyyyMMdd")}.xlsx");

            //return Ok();
        }


        /// <summary>
        /// 下载模板文件
        /// </summary>
        /// <returns></returns>
        [HttpPost("download")]
        public IActionResult DownloadTemplate()
        {
            var temploateFilePath = "wwwroot/template/employee_template.xlsx";

            if(System.IO.File.Exists(temploateFilePath))
            {
                byte[] bytes = System.IO.File.ReadAllBytes(temploateFilePath);
                var stream = new FileStream(temploateFilePath, FileMode.Open,FileAccess.Read);
                return File(stream, "application/octet-stream;charset=utf8",$"{Guid.NewGuid():N}.xlsx");
            }

            return Ok();
        }


        [HttpGet("employee/info")]
        public IActionResult ExportEmployeeInfo()
        {
            //获取所有要导出的员工信息
            var data = _service.GetEmployee();


            //获取模板文件
            var filePath = "wwwroot/template/temploate_employee_info.xlsx";

            //拿到这个文件的工作薄
            var book = new NPOI.XSSF.UserModel.XSSFWorkbook(filePath);
            
            //拿到这个模板文件的sheet（之后所有的sheet都是这个模板）
            var sheet = book.GetSheet("sheet1");

            //有多少个员工，就有多少个sheet
            int i = 1;
            data.ForEach(x =>
            {
                var sh = sheet.CopySheet(x.Name);

                sh.GetRow(2).GetCell(1).SetCellValue($"00{i}");
                sh.GetRow(3).GetCell(1).SetCellValue(x.Name);
                sh.GetRow(3).GetCell(4).SetCellValue(x.Gender);
                sh.GetRow(4).GetCell(1).SetCellValue(x.Native);
                sh.GetRow(4).GetCell(5).SetCellValue(x.IsMarry == true?"已婚":"未婚");
                i++;
            });
            book.RemoveSheetAt(0);


            //下载这个文件
            MemoryStream ms = new MemoryStream();
            book.Write(ms);
            byte[] bytes = ms.ToArray();
            return File(bytes, "application/-excel", $"{System.DateTime.Now.ToString("yyyyMMdd")}.xlsx");
        }

    }
}
